package cn.hackcloud.concurrency.lach;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 实现
 * Created by www.ibfbc.com
 */
public class CountDownLatch extends Latch {
    private final Runnable runnable;

    public CountDownLatch(int limit, Runnable runnable) {
        super(limit);
        this.runnable = runnable;
    }

    @Override
    public void await() throws InterruptedException {
        synchronized (this) {
            //当limit>0时，当前线程进入阻塞
            while (limit > 0) {
                this.wait();
            }
        }
        if (null != runnable) {
            runnable.run();
        }
    }

    @Override
    public void await(TimeUnit timeUnit, long times) throws InterruptedException, TimeoutException {
        if (times <= 0)
            throw new IllegalArgumentException("the time is invalid.");
        //转为纳秒
        long remainingNanos = timeUnit.toNanos(times);
        final long endNanos = System.nanoTime() + remainingNanos;
        synchronized (this) {
            while (limit > 0) {
                //超时则异常
                if (TimeUnit.NANOSECONDS.toMillis(remainingNanos) <= 0) {
                    throw new TimeoutException("wait time out.");
                }
                //等待remainingNanos，在等待过程中可能被中断，需要重新计算等待remainingNanos
                this.wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos));
                remainingNanos = endNanos - System.nanoTime();
            }
        }

    }

    @Override
    public void countDown() {
        synchronized (this) {
            if (limit <= 0) {
                throw new IllegalStateException("");
            }
            //使计数器-1,并且通知阻塞线程
            limit--;
            this.notifyAll();
        }
    }

    @Override
    public int getActive() {
        return limit;
    }
}
